package main

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"math/big"
	"net/http"
	"os"

	"github.com/gin-gonic/gin"
)

var privateKey *rsa.PrivateKey
var crt *x509.Certificate
var rootCertificate = "-----BEGIN CERTIFICATE-----\n" +
	"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\n" +
	"-----END CERTIFICATE-----\n"

type License struct {
	LicenseID          string    `json:"licenseId"`
	LicenseeName       string    `json:"licenseeName"`
	AssigneeName       string    `json:"assigneeName"`
	AssigneeEmail      string    `json:"assigneeEmail"`
	LicenseRestriction string    `json:"licenseRestriction"`
	CheckConcurrentUse bool      `json:"checkConcurrentUse"`
	Products           []Product `json:"products"`
	Metadata           string    `json:"metadata"`
	Hash               string    `json:"hash"`
	GracePeriodDays    int       `json:"gracePeriodDays"`
	AutoProlongated    bool      `json:"autoProlongated"`
	IsAutoProlongated  bool      `json:"isAutoProlongated"`
}

type Product struct {
	Code         string `json:"code"`
	FallbackDate string `json:"fallbackDate"`
	PaidUpTo     string `json:"paidUpTo"`
	Extended     bool   `json:"extended"`
}

func generateLicenseID() string {
	const allowedCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	const licenseLength = 10
	b := make([]byte, licenseLength)
	for i := range b {
		index, _ := rand.Int(rand.Reader, big.NewInt(int64(len(allowedCharacters))))
		b[i] = allowedCharacters[index.Int64()]
	}
	return string(b)
}

func generateLicense(c *gin.Context) {

	var license License
	if err := c.ShouldBindJSON(&license); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	license.LicenseID = generateLicenseID()
	licenseStr, _ := json.Marshal(license)
	fmt.Printf("licenseStr:%s\n", licenseStr)
	// Sign the license using SHA1withRSA
	hashed := sha1.Sum(licenseStr)
	signature, _ := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA1, hashed[:])

	licensePartBase64 := base64.StdEncoding.EncodeToString(licenseStr)
	signatureBase64 := base64.StdEncoding.EncodeToString(signature)
	crtBase64 := base64.StdEncoding.EncodeToString(crt.Raw)

	licenseResult := fmt.Sprintf("%s-%s-%s-%s", license.LicenseID, licensePartBase64, signatureBase64, crtBase64)
	fmt.Printf("licenseResult:%s\n", licenseResult)
	c.JSON(http.StatusOK, gin.H{"license": licenseResult})
}

func index(c *gin.Context) {
	c.HTML(http.StatusOK, "/index.html", gin.H{
		"title":        "请选择",
		"licenseeName": "Evaluator",
		"assigneeName": "Evaluator",
		"expiryDate":   "2099-12-31",
	})
}

// 生成power.conf配置
func generateEqualResult() {

	// fmt.Println("x：证书的签名密文")
	x := new(big.Int).SetBytes(crt.Signature)
	// fmt.Println(x)

	// fmt.Println("y：证书指数 固定65537")
	y := 65537
	// fmt.Println(y)

	block, _ := pem.Decode([]byte(rootCertificate))
	rootCertificate, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		panic("解析 rootCertificate 报错, 原因: " + err.Error())
	}

	// 其实是个固定的值，这里计算出来也行 jetbra-Z.txt里面
	// fmt.Println("z：jetbra的内置根证书的公钥")
	p, _ := rootCertificate.PublicKey.(*rsa.PublicKey)
	z := p.N
	// fmt.Println(z)

	zp, _ := crt.PublicKey.(*rsa.PublicKey)
	r := new(big.Int)
	// 对证书验证其实就是验证证书中携带的签名是否和jetbains计算的签名是否一致，jetbrains会使用其内置根证书z尝试对签名解密，
	// 即计算：x.modpow(y,z)（https://www.xuzhengtong.com/2022/07/25/secure/RSA/），但是这里的证书不是由jetbrains签发，所以要替换计算的结果为fakeResult，EQUAL,x,y,z->fakeResult中
	r.Exp(x, big.NewInt(int64(y)), zp.N)
	// fmt.Printf("r：modpow计算得到\n")
	// fmt.Println(r)

	fmt.Printf("EQUAL,%d,%d,%d->%d", x, y, z, r)
}

func cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		origin := c.Request.Header.Get("Origin")

		if origin != "" {
			c.Header("Access-Control-Allow-Origin", "*") // 可将将 * 替换为指定的域名
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
			c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
			c.Header("Access-Control-Allow-Credentials", "true")
		}
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}
		c.Next()
	}
}

func init() {
	// Load private key and certificate
	privateKeyPEM, err := os.ReadFile("./jetbra.key")
	if err != nil {
		panic("读取 jetbra.key 报错, 原因: " + err.Error())
	}

	block, _ := pem.Decode(privateKeyPEM)

	privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		panic("解析 jetbra.key 报错, 原因: " + err.Error())
	}

	crtPEM, err := os.ReadFile("./jetbra.pem")
	if err != nil {
		panic("读取 jetbra.pem 报错, 原因: " + err.Error())
	}
	block, _ = pem.Decode(crtPEM)
	crt, err = x509.ParseCertificate(block.Bytes)
	if err != nil {
		panic("解析 jetbra.pem 报错, 原因: " + err.Error())
	}
}

func main() {
	//初始化路由
	r := gin.Default()
	r.Use(cors())
	r.Static("static", "static")
	//加载模板
	r.LoadHTMLGlob("templates/*")
	r.GET("/", index)
	r.POST("/generateLicense", generateLicense)
	r.Run("0.0.0.0:8080")
}
